package com.netty.clientserver.strategy.impl;

import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.netty.clientserver.command.Command;
import com.netty.clientserver.packet.GroupMessage;
import com.netty.clientserver.packet.base.Packet;
import com.netty.clientserver.packet.bo.GroupMessageBo;
import com.netty.clientserver.packet.response.ResponseVo;
import com.netty.clientserver.strategy.TypeStrategy;
import com.netty.clientserver.util.ConnectUtils;
import com.netty.common.constant.MqConstants;
import com.netty.common.entity.Message;
import com.netty.common.entity.User;
import com.netty.common.entity.mq.MqMessage;
import com.netty.common.enums.TypeEnum;
import com.netty.common.util.RedisUtil;
import com.netty.common.util.UUID;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.mbeans.GroupMBean;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/** 群聊消息
 * @author LiuXiaoYu
 * @date 2022/2/3- 14:23
 */
@Component("9")
@DependsOn("mqConfig")
@Slf4j
public class GroupMessageTypeStrategyImpl implements TypeStrategy {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisUtil redisUtil;
    @Override
    public Packet execute(Channel channel, String type, String content) {
        //转换
        GroupMessageBo groupMessageBo = JSONObject.parseObject(content, new TypeReference<GroupMessageBo>() {});
        GroupMessage groupMessage = new GroupMessage();
        //复制属性
        BeanUtils.copyProperties(groupMessageBo,groupMessage);

        String userIdList = groupMessage.getUserIdList();
        List<String> userIds = Arrays.stream(userIdList.split(",")).collect(Collectors.toList());
    /*    BindHandler已经绑定 userId和Channel 并且将channel加入了ChannelGroup
        但是并没有区分哪些是群聊/私聊的channel 通过Map中的boolean值来判断是否是群聊channel*/
        String sendMessage=groupMessage.getMessage();
        String owner=groupMessage.getOwner();
        String ownerId=String.valueOf(groupMessage.getOwnerId());
        String ownerImage=groupMessage.getOwnerImage();
        //不论群成员是否在线 都要把消息入库
        String uuid=groupMessage.getUuid();
        if (uuid==null){
            groupMessage.setUuid(UUID.getUUID());
        }
        //构建mq日志
        String userIdInMap = ConnectUtils.getUserId(channel);
        //判断收到消息的人是否在线
        //这是真正的入库消息
        com.netty.common.entity.Message msg=new com.netty.common.entity.Message()
                .setInfoContent(sendMessage)
                .setToId(groupMessage.getToId())
                //默认群聊消息都是online
                .setOnline(true)
                .setFromId(Integer.parseInt(userIdInMap))
                .setSingleMessage(Integer.parseInt(type)==1)
                .setSendTime(new Date());

        String messageToDataBase= JSON.toJSONString(msg);
        //生成mq消息日志log 即MqMessage 这是存储在mq的消息日志
        MqMessage messageLog = new MqMessage()
                .setMessage(messageToDataBase)
                .setMessageId(groupMessage.getUuid())
                .setExchange(MqConstants.NETTY_MESSAGE_EXCHANGE)
                .setRoutingKey(MqConstants.NETTY_MESSAGE_ROUTING_KEY)
                //设置状态0：投递中
                .setStatus(MqConstants.MESSAGE_DELIVERED)
                //设置重试次数为0
                .setRetryCount(MqConstants.MESSAGE_RETRY_COUNT);
        //存放到redis里面 可能会出现网络故障 没有存储进去
        redisUtil.set(MqConstants.NETTY_MESSAGE_LOG_KEY+groupMessage.getUuid(),messageLog);
        //不论对方是否在线都要mq发消息入库(clientserver)
        org.springframework.amqp.core.Message message = MessageBuilder.withBody(messageToDataBase.getBytes()).setMessageId(groupMessage.getUuid()).build();
        rabbitTemplate.convertAndSend(messageLog.getExchange(),messageLog.getRoutingKey(),message,new CorrelationData(groupMessage.getUuid()));
        for (String userId:userIds){
            //判断群聊成员是否在线
            Channel memberChannel = ConnectUtils.isBind(userId);
            //但是这个memberChannel可能不是这个toId即groupId的群聊channel

            //判断用户是否已经登录
            if (memberChannel!=null) {
                //说明该用户登陆了 但不确定是群聊还是私聊
                if (ConnectUtils.isThisGroupChannel(String.valueOf(groupMessage.getToId()),memberChannel)){
                    //说明是这个群的群聊channel
                    //直接向每个在线的群成员推送消息
                    //但是要排除自己
                    if (!ownerId.equals(userId)){
                        //构造指定格式
                        ByteBuf byteBuf = getByteBuf(memberChannel,sendMessage,owner,ownerImage,userIds);
                        //向群里的其他在线成员推送消息
                        memberChannel.writeAndFlush(new TextWebSocketFrame(byteBuf));
                    }
                }
            }
//            else {
//                //说明该成员不在线 直接存入
//
//            }
        }
        return groupMessage;
    }

        /**
     * 封装创建群组的响应数据格式
     * @param channel
     * @return
     */
    public ByteBuf getByteBuf(Channel channel,String message,String owner,String ownerImage,List<String> userIdList) {
        ByteBuf byteBuf = channel.alloc().buffer();
        ResponseVo responseVo = new ResponseVo()
                .setType(Command.GROUP_MESSAGE_RESPONSE)
                .setMessage(message)
                .setUserIdList(userIdList)
                .setOwner(owner)
                .setOwnerImage(ownerImage)
                .setDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                .setStatus(HttpStatus.HTTP_OK);
        byte []bytes =  JSONObject.toJSONString(responseVo).getBytes(StandardCharsets.UTF_8);
        byteBuf.writeBytes(bytes);
        return byteBuf;
    }
}

